Test Failed
Push — main ( 83e7c8...0c12e7 )
by chief
09:12
created

jquery.plupload.queue.js ➔ handleStatus   C

Complexity

Conditions 11

Size

Total Lines 24
Code Lines 13

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
eloc 13
dl 0
loc 24
c 0
b 0
f 0
rs 5.4
cc 11

How to fix   Complexity   

Complexity

Complex classes like jquery.plupload.queue.js ➔ handleStatus often do a lot of different things. To break such a class down, we need to identify a cohesive component within that class. A common approach to find such a component is to look for fields/methods that share the same prefixes, or suffixes.

Once you have determined the fields that belong together, you can apply the Extract Class refactoring. If the component makes sense as a sub-class, Extract Subclass is also a candidate, and is often faster.

1
/**
2
 * jquery.plupload.queue.js
3
 *
4
 * Copyright 2009, Moxiecode Systems AB
5
 * Released under GPL License.
6
 *
7
 * License: http://www.plupload.com/license
8
 * Contributing: http://www.plupload.com/contributing
9
 */
10
11
/* global jQuery:true, alert:true */
12
13
/**
14
jQuery based implementation of the Plupload API - multi-runtime file uploading API.
15
16
To use the widget you must include _jQuery_. It is not meant to be extended in any way and is provided to be
17
used as it is.
18
19
@example
20
	<!-- Instantiating: -->
21
	<div id="uploader">
22
		<p>Your browser doesn't have Flash, Silverlight or HTML5 support.</p>
23
	</div>
24
25
	<script>
26
		$('#uploader').pluploadQueue({
27
			url : '../upload.php',
28
			filters : [
29
				{title : "Image files", extensions : "jpg,gif,png"}
30
			],
31
			rename: true,
32
			flash_swf_url : '../../js/Moxie.swf',
33
			silverlight_xap_url : '../../js/Moxie.xap',
34
		});
35
	</script>
36
37
@example
38
	// Retrieving a reference to plupload.Uploader object
39
	var uploader = $('#uploader').pluploadQueue();
40
41
	uploader.bind('FilesAdded', function() {
42
43
		// Autostart
44
		setTimeout(uploader.start, 1); // "detach" from the main thread
45
	});
46
47
@class pluploadQueue
48
@constructor
49
@param {Object} settings For detailed information about each option check documentation.
50
	@param {String} settings.url URL of the server-side upload handler.
51
	@param {Number|String} [settings.chunk_size=0] Chunk size in bytes to slice the file into. Shorcuts with b, kb, mb, gb, tb suffixes also supported. `e.g. 204800 or "204800b" or "200kb"`. By default - disabled.
52
	@param {String} [settings.file_data_name="file"] Name for the file field in Multipart formated message.
53
	@param {Array} [settings.filters=[]] Set of file type filters, each one defined by hash of title and extensions. `e.g. {title : "Image files", extensions : "jpg,jpeg,gif,png"}`. Dispatches `plupload.FILE_EXTENSION_ERROR`
54
	@param {String} [settings.flash_swf_url] URL of the Flash swf.
55
	@param {Object} [settings.headers] Custom headers to send with the upload. Hash of name/value pairs.
56
	@param {Number|String} [settings.max_file_size] Maximum file size that the user can pick, in bytes. Optionally supports b, kb, mb, gb, tb suffixes. `e.g. "10mb" or "1gb"`. By default - not set. Dispatches `plupload.FILE_SIZE_ERROR`.
57
	@param {Number} [settings.max_retries=0] How many times to retry the chunk or file, before triggering Error event.
58
	@param {Boolean} [settings.multipart=true] Whether to send file and additional parameters as Multipart formated message.
59
	@param {Object} [settings.multipart_params] Hash of key/value pairs to send with every file upload.
60
	@param {Boolean} [settings.multi_selection=true] Enable ability to select multiple files at once in file dialog.
61
	@param {Boolean} [settings.prevent_duplicates=false] Do not let duplicates into the queue. Dispatches `plupload.FILE_DUPLICATE_ERROR`.
62
	@param {String|Object} [settings.required_features] Either comma-separated list or hash of required features that chosen runtime should absolutely possess.
63
	@param {Object} [settings.resize] Enable resizng of images on client-side. Applies to `image/jpeg` and `image/png` only. `e.g. {width : 200, height : 200, quality : 90, crop: true}`
64
		@param {Number} [settings.resize.width] If image is bigger, it will be resized.
65
		@param {Number} [settings.resize.height] If image is bigger, it will be resized.
66
		@param {Number} [settings.resize.quality=90] Compression quality for jpegs (1-100).
67
		@param {Boolean} [settings.resize.crop=false] Whether to crop images to exact dimensions. By default they will be resized proportionally.
68
	@param {String} [settings.runtimes="html5,flash,silverlight,html4"] Comma separated list of runtimes, that Plupload will try in turn, moving to the next if previous fails.
69
	@param {String} [settings.silverlight_xap_url] URL of the Silverlight xap.
70
	@param {Boolean} [settings.unique_names=false] If true will generate unique filenames for uploaded files.
71
72
	@param {Boolean} [settings.dragdrop=true] Enable ability to add file to the queue by drag'n'dropping them from the desktop.
73
	@param {Boolean} [settings.rename=false] Enable ability to rename files in the queue.
74
	@param {Boolean} [settings.multiple_queues=true] Re-activate the widget after each upload procedure.
75
*/
76
;(function($, plupload) {
77
	var uploaders = {};
78
79
	function _(str) {
80
		return plupload.translate(str) || str;
81
	}
82
83
	function renderUI(id, target) {
84
		// Remove all existing non plupload items
85
		target.contents().each(function(i, node) {
86
			node = $(node);
87
88
			if (!node.is('.plupload')) {
89
				node.remove();
90
			}
91
		});
92
93
		target.prepend(
94
			'<div class="plupload_wrapper plupload_scroll">' +
95
				'<div id="' + id + '_container" class="plupload_container">' +
96
					'<div class="plupload">' +
97
						'<div class="plupload_header">' +
98
							'<div class="plupload_header_content">' +
99
								'<div class="plupload_header_title">' + _('Select files') + '</div>' +
100
								'<div class="plupload_header_text">' + _('Add files to the upload queue and click the start button.') + '</div>' +
101
							'</div>' +
102
						'</div>' +
103
104
						'<div class="plupload_content">' +
105
							'<div class="plupload_filelist_header">' +
106
								'<div class="plupload_file_name">' + _('Filename') + '</div>' +
107
								'<div class="plupload_file_action">&nbsp;</div>' +
108
								'<div class="plupload_file_status"><span>' + _('Status') + '</span></div>' +
109
								'<div class="plupload_file_size">' + _('Size') + '</div>' +
110
								'<div class="plupload_clearer">&nbsp;</div>' +
111
							'</div>' +
112
113
							'<ul id="' + id + '_filelist" class="plupload_filelist"></ul>' +
114
115
							'<div class="plupload_filelist_footer">' +
116
								'<div class="plupload_file_name">' +
117
									'<div class="plupload_buttons">' +
118
										'<a href="#" class="plupload_button plupload_add" id="' + id + '_browse">' + _('Add Files') + '</a>' +
119
										'<a href="#" class="plupload_button plupload_start">' + _('Start Upload') + '</a>' +
120
									'</div>' +
121
									'<span class="plupload_upload_status"></span>' +
122
								'</div>' +
123
								'<div class="plupload_file_action"></div>' +
124
								'<div class="plupload_file_status"><span class="plupload_total_status">0%</span></div>' +
125
								'<div class="plupload_file_size"><span class="plupload_total_file_size">0 b</span></div>' +
126
								'<div class="plupload_progress">' +
127
									'<div class="plupload_progress_container">' +
128
										'<div class="plupload_progress_bar"></div>' +
129
									'</div>' +
130
								'</div>' +
131
								'<div class="plupload_clearer">&nbsp;</div>' +
132
							'</div>' +
133
						'</div>' +
134
					'</div>' +
135
				'</div>' +
136
				'<input type="hidden" id="' + id + '_count" name="' + id + '_count" value="0" />' +
137
			'</div>'
138
		);
139
	}
140
141
	$.fn.pluploadQueue = function(settings) {
142
		if (settings) {
143
			this.each(function() {
144
				var uploader, target, id, contents_bak;
145
146
				target = $(this);
147
				id = target.attr('id');
148
149
				if (!id) {
150
					id = plupload.guid();
151
					target.attr('id', id);
152
				}
153
154
				contents_bak = target.html();
155
				renderUI(id, target);
156
157
				settings = $.extend({
158
					dragdrop : true,
159
					browse_button : id + '_browse',
160
					container : id
161
				}, settings);
162
163
				// Enable drag/drop (see PostInit handler as well)
164
				if (settings.dragdrop) {
165
					settings.drop_element = id + '_filelist';
166
				}
167
168
				uploader = new plupload.Uploader(settings);
169
170
				uploaders[id] = uploader;
171
172
				function handleStatus(file) {
173
					var actionClass;
174
175
					if (file.status == plupload.DONE) {
176
						actionClass = 'plupload_done';
177
					}
178
179
					if (file.status == plupload.FAILED) {
180
						actionClass = 'plupload_failed';
181
					}
182
183
					if (file.status == plupload.QUEUED) {
184
						actionClass = 'plupload_delete';
185
					}
186
187
					if (file.status == plupload.UPLOADING) {
188
						actionClass = 'plupload_uploading';
189
					}
190
191
					var icon = $('#' + file.id).attr('class', actionClass).find('a').css('display', 'block');
0 ignored issues
show
Bug introduced by
The variable actionClass does not seem to be initialized in case file.status == plupload.DONE on line 175 is false. Are you sure the function attr handles undefined variables?
Loading history...
192
					if (file.hint) {
193
						icon.attr('title', file.hint);
194
					}
195
				}
196
197
				function updateTotalProgress() {
198
					$('span.plupload_total_status', target).html(uploader.total.percent + '%');
199
					$('div.plupload_progress_bar', target).css('width', uploader.total.percent + '%');
200
					$('span.plupload_upload_status', target).html(
201
						plupload.sprintf(_('Uploaded %d/%d files'), uploader.total.uploaded, uploader.files.length)
202
					);
203
				}
204
205
				function updateList() {
206
					var fileList = $('ul.plupload_filelist', target).html(''), inputCount = 0, inputHTML;
207
208
					$.each(uploader.files, function(i, file) {
209
						inputHTML = '';
210
211
						if (file.status == plupload.DONE) {
212
							if (file.target_name) {
213
								inputHTML += '<input type="hidden" name="' + id + '_' + inputCount + '_tmpname" value="' + plupload.xmlEncode(file.target_name) + '" />';
214
							}
215
216
							inputHTML += '<input type="hidden" name="' + id + '_' + inputCount + '_name" value="' + plupload.xmlEncode(file.name) + '" />';
217
							inputHTML += '<input type="hidden" name="' + id + '_' + inputCount + '_status" value="' + (file.status == plupload.DONE ? 'done' : 'failed') + '" />';
218
219
							inputCount++;
220
221
							$('#' + id + '_count').val(inputCount);
222
						}
223
224
						fileList.append(
225
							'<li id="' + file.id + '">' +
226
								'<div class="plupload_file_name"><span>' + file.name + '</span></div>' +
227
								'<div class="plupload_file_action"><a href="#"></a></div>' +
228
								'<div class="plupload_file_status">' + file.percent + '%</div>' +
229
								'<div class="plupload_file_size">' + plupload.formatSize(file.size) + '</div>' +
230
								'<div class="plupload_clearer">&nbsp;</div>' +
231
								inputHTML +
232
							'</li>'
233
						);
234
235
						handleStatus(file);
236
237
						$('#' + file.id + '.plupload_delete a').click(function(e) {
238
							$('#' + file.id).remove();
239
							uploader.removeFile(file);
240
241
							e.preventDefault();
242
						});
243
					});
244
245
					$('span.plupload_total_file_size', target).html(plupload.formatSize(uploader.total.size));
246
247
					if (uploader.total.queued === 0) {
248
						$('span.plupload_add_text', target).html(_('Add Files'));
249
					} else {
250
						$('span.plupload_add_text', target).html(plupload.sprintf(_('%d files queued'), uploader.total.queued));
251
					}
252
253
					$('a.plupload_start', target).toggleClass('plupload_disabled', uploader.files.length == (uploader.total.uploaded + uploader.total.failed));
254
255
					// Scroll to end of file list
256
					fileList[0].scrollTop = fileList[0].scrollHeight;
257
258
					updateTotalProgress();
259
260
					// Re-add drag message if there is no files
261
					if (!uploader.files.length && uploader.features.dragdrop && uploader.settings.dragdrop) {
262
						$('#' + id + '_filelist').append('<li class="plupload_droptext">' + _("Drag files here.") + '</li>');
263
					}
264
				}
265
266
				function destroy() {
267
					delete uploaders[id];
268
					uploader.destroy();
269
					target.html(contents_bak);
270
					uploader = target = contents_bak = null;
271
				}
272
273
				uploader.bind("UploadFile", function(up, file) {
274
					$('#' + file.id).addClass('plupload_current_file');
275
				});
276
277
				uploader.bind('Init', function(up, res) {
278
					// Enable rename support
279
					if (!settings.unique_names && settings.rename) {
280
						target.on('click', '#' + id + '_filelist div.plupload_file_name span', function(e) {
281
							var targetSpan = $(e.target), file, parts, name, ext = "";
282
							var fileContainer = targetSpan.closest('li');
283
284
							if (!fileContainer.hasClass('plupload_delete')) {
285
								return;
286
							}
287
288
							// Get file name and split out name and extension
289
							file = up.getFile(targetSpan.parents('li')[0].id);
290
							name = file.name;
291
							parts = /^(.+)(\.[^.]+)$/.exec(name);
292
							if (parts) {
293
								name = parts[1];
294
								ext = parts[2];
295
							}
296
297
							// Display input element
298
							targetSpan.hide().after('<input type="text" />');
299
							targetSpan.next().val(name).focus().blur(function() {
300
								targetSpan.show().next().remove();
301
							}).keydown(function(e) {
302
								var targetInput = $(this);
303
304
								if (e.keyCode == 13) {
305
									e.preventDefault();
306
307
									// Rename file and glue extension back on
308
									file.name = targetInput.val() + ext;
309
									targetSpan.html(file.name);
310
									targetInput.blur();
311
								}
312
							});
313
						});
314
					}
315
316
					$('#' + id + '_container').attr('title', 'Using runtime: ' + res.runtime);
317
318
					$('a.plupload_start', target).click(function(e) {
319
						if (!$(this).hasClass('plupload_disabled')) {
320
							uploader.start();
321
						}
322
323
						e.preventDefault();
324
					});
325
326
					$('a.plupload_stop', target).click(function(e) {
327
						e.preventDefault();
328
						uploader.stop();
329
					});
330
331
					$('a.plupload_start', target).addClass('plupload_disabled');
332
				});
333
334
				uploader.bind("Error", function(up, err) {
335
					var file = err.file, message;
336
337
					if (file) {
338
						message = err.message;
339
340
						if (err.details) {
341
							message += " (" + err.details + ")";
342
						}
343
344
						if (err.code == plupload.FILE_SIZE_ERROR) {
345
							alert(_("Error: File too large:") + " " + file.name);
0 ignored issues
show
Debugging Code Best Practice introduced by
The alert UI element is often considered obtrusive and is generally only used as a temporary measure. Consider replacing it with another UI element.
Loading history...
346
						}
347
348
						if (err.code == plupload.FILE_EXTENSION_ERROR) {
349
							alert(_("Error: Invalid file extension:") + " " + file.name);
350
						}
351
352
						file.hint = message;
353
						$('#' + file.id).attr('class', 'plupload_failed').find('a').css('display', 'block').attr('title', message);
354
					}
355
356
					if (err.code === plupload.INIT_ERROR) {
357
						setTimeout(function() {
358
							destroy();
359
						}, 1);
360
					}
361
				});
362
363
				uploader.bind("PostInit", function(up) {
364
					// features are populated only after input components are fully instantiated
365
					if (up.settings.dragdrop && up.features.dragdrop) {
366
						$('#' + id + '_filelist').append('<li class="plupload_droptext">' + _("Drag files here.") + '</li>');
367
					}
368
				});
369
370
				uploader.init();
371
372
				uploader.bind('StateChanged', function() {
373
					if (uploader.state === plupload.STARTED) {
374
						$('li.plupload_delete a,div.plupload_buttons', target).hide();
375
						uploader.disableBrowse(true);
376
377
						$('span.plupload_upload_status,div.plupload_progress,a.plupload_stop', target).css('display', 'block');
378
						$('span.plupload_upload_status', target).html('Uploaded ' + uploader.total.uploaded + '/' + uploader.files.length + ' files');
379
380
						if (settings.multiple_queues) {
381
							$('span.plupload_total_status,span.plupload_total_file_size', target).show();
382
						}
383
					} else {
384
						updateList();
385
						$('a.plupload_stop,div.plupload_progress', target).hide();
386
						$('a.plupload_delete', target).css('display', 'block');
387
388
						if (settings.multiple_queues && uploader.total.uploaded + uploader.total.failed == uploader.files.length) {
389
							$(".plupload_buttons,.plupload_upload_status", target).css("display", "inline");
390
							uploader.disableBrowse(false);
391
392
							$(".plupload_start", target).addClass("plupload_disabled");
393
							$('span.plupload_total_status,span.plupload_total_file_size', target).hide();
394
						}
395
					}
396
				});
397
398
				uploader.bind('FilesAdded', updateList);
399
400
				uploader.bind('FilesRemoved', function() {
401
					// since the whole file list is redrawn for every change in the queue
402
					// we need to scroll back to the file removal point to avoid annoying
403
					// scrolling to the bottom bug (see #926)
404
					var scrollTop = $('#' + id + '_filelist').scrollTop();
405
					updateList();
406
					$('#' + id + '_filelist').scrollTop(scrollTop);
407
				});
408
409
				uploader.bind('FileUploaded', function(up, file) {
410
					handleStatus(file);
411
				});
412
413
				uploader.bind("UploadProgress", function(up, file) {
414
					// Set file specific progress
415
					$('#' + file.id + ' div.plupload_file_status', target).html(file.percent + '%');
416
417
					handleStatus(file);
418
					updateTotalProgress();
419
				});
420
421
				// Call setup function
422
				if (settings.setup) {
423
					settings.setup(uploader);
424
				}
425
			});
426
427
			return this;
428
		} else {
0 ignored issues
show
Comprehensibility introduced by
else is not necessary here since all if branches return, consider removing it to reduce nesting and make code more readable.
Loading history...
429
			// Get uploader instance for specified element
430
			return uploaders[$(this[0]).attr('id')];
431
		}
432
	};
433
})(jQuery, plupload);
0 ignored issues
show
Bug introduced by
The variable plupload seems to be never declared. If this is a global, consider adding a /** global: plupload */ comment.

This checks looks for references to variables that have not been declared. This is most likey a typographical error or a variable has been renamed.

To learn more about declaring variables in Javascript, see the MDN.

Loading history...
434